#include "MapKnowledge.hh"


void 
cache_state_info_t::update_map_knowledge_before_turn(State & state)
{

  //
  // Keep trace of enemy's Hills
  //
  std::set<Ant>::iterator ant_it=enemyHills.begin();
  //erase out of date information
  while(ant_it!=enemyHills.end())
    {
      std::set<Ant>::iterator next=ant_it;
      next++;
      if(state.location(ant_it->loc).isVisible)
	{
	  if(not state.location(ant_it->loc).isHill)
	    enemyHills.erase(ant_it);
	  else
	    {
	      ASSERT(state.location(ant_it->loc).hillPlayer == (signed) ant_it->team);
	    }
	}
      ant_it=next;
    }

  //update places we can see now
  enemyHills.insert(state.enemyHills.begin(),state.enemyHills.end());
  //mix places from sight and memory
  state.enemyHills.assign(enemyHills.begin(),enemyHills.end());


  //
  // Keep trace of my onw Hills
  //
  std::set<uLocation>::iterator it=myHills.begin();
  //erase out of date information
  while(it!=myHills.end())
    {
      std::set<uLocation>::iterator next=it;
      next++;
      if(state.location(*it).isVisible)
	{
	  if(not state.location(*it).isHill)
	    {
	      myHills.erase(it);
	    }
	  else
	    {
	      ASSERT(state.location(*it).hillPlayer == 0);
	    }
	}
      it=next;
    }

  //update places we can see now
  myHills.insert(state.myHills.begin(),state.myHills.end());
  //mix places from sight and memory
  state.myHills.assign(myHills.begin(),myHills.end());



  it=food.begin();
  //erase out of date information
  while(it!=food.end())
    {
      std::set<uLocation>::iterator next=it;
      next++;
      if(state.location(*it).isVisible)
	if(not state.location(*it).isFood)
	  food.erase(it);
      it=next;
    }

  //update places we can see now
  food.insert(state.food.begin(),state.food.end());
  //mix places from sight and memory
  state.food.assign(food.begin(),food.end());
}


/// Count reachable enemies according to the rules if one ant of team is at loc
unsigned count_reachable_enemies(Map<Square> & map, uLocation sLoc, signed team)
{
  unsigned enemies = 0;

  for(CacheMap::reach_iterator it_loc=torus.attack_begin(sLoc);
      it_loc != torus.attack_end(sLoc); ++ it_loc)
    {
      uLocation cLoc = *it_loc;
      if(mayBeEnemy(map[cLoc],team)) enemies++;
    }

  return enemies;
}


/// evaluates if a position is expected to die
bool will_die(Map<Square> & map, uLocation sLoc, signed team)
{
  ASSERT(torus.size);
  unsigned enemies = count_reachable_enemies(map, sLoc,team);
  bool die = false;

  for(CacheMap::reach_iterator it_loc=torus.attack_begin(sLoc);
      it_loc != torus.attack_end(sLoc) and not die; 
      ++ it_loc) 
    {
      uLocation cLoc = *it_loc;
      if(map[cLoc].ant != -1 and map[cLoc].ant != team)
        die = count_reachable_enemies(map, cLoc, map[cLoc].ant) <= enemies;
    }
  return die;
}




/// Used at the end of turn to update hive estimate
/// Hive estimate is usefull to protect Hills: 
/// unlock the door at need allow to spawn new ants
bool this_food_is_for_me(Map<Square> & map, uLocation fLoc, signed team)
{
  ASSERT(torus.size);
  ASSERT(map[fLoc].isFood or not map[fLoc].isVisible);
  unsigned enemies = 0;
  unsigned friends = 0;
  
  
  for(CacheMap::reach_iterator it_loc=torus.food_begin(fLoc);
      it_loc != torus.food_end(fLoc); ++ it_loc)
    {
      uLocation cLoc = *it_loc;
      if(map[cLoc].ant != -1 and not will_die(map, cLoc, map[cLoc].ant))
	{
	  if(isEnemy(map.at(cLoc),team)) enemies++;
	  else friends++;
	}
    }
  return friends>0 and enemies==0;
}





void 
hive_estimator_t::update_hive_estimate_before_turn(State & state)
{
  TRACK();
  ASSERT(p_myHills);
  
  if(state.turn==1)
    {
      guards = p_myHills->size();
    }
  
  
  unsigned ants_at_hill = 0;
  for(std::vector<uLocation>::const_iterator it_hill=p_myHills->begin();
      it_hill!=p_myHills->end(); ++it_hill)
    {
      if(isFriend(state.map[*it_hill],0)) ants_at_hill++;
    }
  hive = hive + guards - ants_at_hill;  
  bug << "hive estimate: " << hive
      << std::endl;
}


void 
hive_estimator_t::update_hive_estimate_after_turn(State & state)
{
  ASSERT(p_food);

  for(std::vector<uLocation>::const_iterator it_food=p_food->begin();
      it_food!=p_food->end(); ++it_food)
    {
      if(this_food_is_for_me(state.map, *it_food))
	hive++;
    }
  
  guards = 0;	
  for(std::vector<uLocation>::const_iterator it_hill=p_myHills->begin();
      it_hill!=p_myHills->end(); ++it_hill)
    {
      if(isFriend(state.map[*it_hill],0)) guards++;
    }
		
}






